﻿using Rookey.Frame.Common;
using Rookey.Frame.Common.Model;
using Rookey.Frame.Common.Network;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using ServiceStack.Caching;
using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Rookey.Frame.Cache.Factory.Provider
{
    /// <summary>
    /// 更新缓存事件参数类
    /// </summary>
    public class UpdateCacheEventArgs : EventArgs
    {
        private string _key;
        /// <summary>
        /// key
        /// </summary>
        public string Key
        {
            get { return _key; }
        }
        private string _ip;
        /// <summary>
        /// ip地址
        /// </summary>
        public string Ip
        {
            get { return _ip; }
        }
        private string _webHost;
        /// <summary>
        /// 站点host
        /// </summary>
        public string WebHost
        {
            get { return _webHost; }
        }
        private string _op;
        /// <summary>
        /// 缓存操作，只针对内存缓存
        /// </summary>
        public string Op
        {
            get { return _op; }
        }
        private string _jsonData;
        /// <summary>
        /// 缓存操作的数据，只针对内存缓存
        /// </summary>
        public string JsonData
        {
            get { return _jsonData; }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="key"></param>
        /// <param name="ip"></param>
        /// <param name="webHost"></param>
        /// <param name="op"></param>
        /// <param name="jsonData"></param>
        public UpdateCacheEventArgs(string key, string ip, string webHost, string op, string jsonData)
        {
            this._key = key;
            this._ip = ip;
            this._webHost = webHost;
            this._op = op;
            this._jsonData = jsonData;
        }
    }

    /// <summary>
    /// Redis缓存提供器
    /// </summary>
    public class RedisCacheProvider : ICacheProvider
    {
        #region 成员属性
        /// <summary>
        /// 客户端链接池
        /// </summary>
        private static PooledRedisClientManager _prcm = null;
        /// <summary>
        /// 发布客户端
        /// </summary>
        private static RedisClient publishRedisClient = null;
        /// <summary>
        /// 订阅客户端
        /// </summary>
        private static RedisClient subscrRedisClient = null;
        /// <summary>
        /// 订阅通道
        /// </summary>
        private const string UPDATE_CACHE_CHANNEL = "update_cache_channel";
        /// <summary>
        /// 消息分隔符
        /// </summary>
        private const string SPLIT_CHAR = "|";
        /// <summary>
        /// 事件代理
        /// </summary>
        /// <param name="o"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public delegate void EventUpdateCache(object o, UpdateCacheEventArgs e);
        /// <summary>
        /// 绑定缓存更新事件
        /// </summary>
        public static event EventUpdateCache BindUpdateCacheEvent;
        private static bool _isConnRedis = false;
        /// <summary>
        /// 是否连接了redis
        /// </summary>
        public static bool IsConnRedis
        {
            get { return _isConnRedis; }
        }
        private static bool _isPubSubscrInited = false;
        /// <summary>
        /// 发布订阅是否已经初始化
        /// </summary>
        public static bool IsPubSubscrInited
        {
            get { return _isPubSubscrInited; }
        }
        private static bool _isCanConnRabbitMq = false; //是否可连接rabbitmq服务
        private static bool _rabbitLinkFlag = false; //rabbitmq连接标识
        private const string RABBIT_EXCHANGE = "update_cache_exchange";
        private const string RABBIT_ROUTINGKEY = "update_cache_routkey";
        private static bool durable = true; //rabiitmq是否持久化
        /// <summary>
        /// 缓存操作-新增
        /// </summary>
        public const string OP_ADD = "add";
        /// <summary>
        /// 缓存操作-编辑
        /// </summary>
        public const string OP_EDIT = "edit";
        /// <summary>
        /// 缓存操作-删除
        /// </summary>
        public const string OP_DEL = "del";
        /// <summary>
        /// 缓存操作-清空
        /// </summary>
        public const string OP_RM = "rm";
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public RedisCacheProvider()
        {
            //发布订阅初始化
            PubSubscrInit();
            //初始化prcm
            InitPrcm();
        }

        #endregion

        #region 临时类
        /// <summary>
        /// 临时类
        /// </summary>
        class TempRedisClass<T> where T : class
        {
            ICacheClient _client = null;
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="client"></param>
            public TempRedisClass(ICacheClient client)
            {
                _client = client;
            }
            /// <summary>
            /// 设置缓存
            /// </summary>
            /// <param name="key">key</param>
            /// <param name="value">value</param>
            /// <returns>是否成功</returns>
            public bool Set(string key, object value)
            {
                if (!IsConnRedis) return false;
                try
                {
                    bool rs = false;
                    using (((RedisClient)_client).AcquireLock(key))
                    {
                        rs = _client.Set<T>(key, value as T);
                    }
                    if (rs)
                    {
                        if (publishRedisClient != null)
                        {
                            try
                            {
                                string msg = string.Format("{0}{1}{2}{1}{3}", key, SPLIT_CHAR, IpAddressHelper.GetLocalIp(), Globals.GetBaseUrl());
                                publishRedisClient.PublishMessage(UPDATE_CACHE_CHANNEL, msg);
                            }
                            catch { }
                        }
                    }
                    return rs;
                }
                catch { }
                return false;
            }
            /// <summary>
            /// 设置缓存值
            /// </summary>
            /// <param name="key">key</param>
            /// <param name="value">value</param>
            /// <param name="slidingExpiration">过期时长</param>
            /// <returns>是否成功</returns>
            public bool SetTimeoutCache(string key, object value, TimeSpan slidingExpiration)
            {
                if (!IsConnRedis) return false;
                try
                {
                    using (((RedisClient)_client).AcquireLock(key))
                    {
                        return _client.Set<T>(key, value as T, slidingExpiration);
                    }
                }
                catch { }
                return false;
            }
            /// <summary>
            /// 设置缓存值
            /// </summary>
            /// <param name="key">key</param>
            /// <param name="value">value</param>
            /// <param name="absoluteExpiration">过期时间</param>
            /// <returns>是否成功</returns>
            public bool SetDateTimeCache(string key, object value, DateTime absoluteExpiration)
            {
                if (!IsConnRedis) return false;
                try
                {
                    using (((RedisClient)_client).AcquireLock(key))
                    {
                        return _client.Set<T>(key, value as T, absoluteExpiration);
                    }
                }
                catch { }
                return false;
            }
        }
        #endregion

        #region 私有函数

        #region redis缓存客户端
        /// <summary>
        /// 创建链接池
        /// </summary>
        /// <param name="readWriteHosts">写主机列表</param>
        /// <param name="readOnlyHosts">读主机列表</param>
        /// <returns></returns>
        private static PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
        {
            //支持读写分离，均衡负载
            return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
            {
                MaxWritePoolSize = 5,//“写”链接池链接数
                MaxReadPoolSize = 5,//“读”链接池链接数
                AutoStart = true,
            });
        }

        /// <summary>
        /// 初始化一个链接池
        /// </summary>
        private static void InitPrcm()
        {
            try
            {
                bool flag = true;
                RedisConfigInfo configInfo = null;
                try
                {
                    string path = WebHelper.GetConfigFilePath("rediscache.config");
                    configInfo = (RedisConfigInfo)XmlHelper.DeserializeFromXML(typeof(RedisConfigInfo), path);
                }
                catch { }
                if (configInfo == null)
                {
                    configInfo = new RedisConfigInfo() { Host = "127.0.0.1", Port = 6379 };
                    flag = false;
                }
                string hostStr = string.Format("{0}:{1}", configInfo.Host, configInfo.Port);
                _prcm = CreateManager(new string[] { hostStr }, new string[] { hostStr });
                _isConnRedis = flag;
            }
            catch { }
        }

        /// <summary>
        /// 获取客户端对象
        /// </summary>
        /// <returns></returns>
        private static ICacheClient GetClient()
        {
            if (_prcm == null)
            {
                InitPrcm();
            }
            return _prcm.GetCacheClient();
        }
        #endregion

        #region rabbitmq相关
        /// <summary>
        /// 获取rabbitmq配置信息
        /// </summary>
        /// <returns></returns>
        private static RabiitMqConfigInfo GetRabbitMqConfig()
        {
            try
            {
                string path = WebHelper.GetConfigFilePath("rabbitmq.config");
                RabiitMqConfigInfo configInfo = (RabiitMqConfigInfo)XmlHelper.DeserializeFromXML(typeof(RabiitMqConfigInfo), path);
                return configInfo;
            }
            catch { }
            return null;
        }
        /// <summary>
        /// 获取rabbitmq连接对象
        /// </summary>
        /// <returns></returns>
        private static IConnection GetRabbitMqConn()
        {
            try
            {
                RabiitMqConfigInfo configInfo = GetRabbitMqConfig();
                if (configInfo != null)
                {
                    var factory = new ConnectionFactory();
                    factory.HostName = configInfo.Host;
                    factory.Port = configInfo.Port;
                    factory.UserName = configInfo.UserName;
                    factory.Password = configInfo.Pwd;
                    var connection = factory.CreateConnection();
                    _isCanConnRabbitMq = true;
                    return connection;
                }
            }
            catch { }
            _isCanConnRabbitMq = false;
            return null;
        }

        /// <summary>
        /// rabbitmq服务是否可用
        /// </summary>
        /// <returns></returns>
        private static bool IsRabbitMqCanConn()
        {
            if (!_rabbitLinkFlag) //第一次连接rabbit服务测试服务是否正常
            {
                IConnection conn = GetRabbitMqConn();
                _rabbitLinkFlag = true;
                return conn != null;
            }
            return _isCanConnRabbitMq;
        }
        #endregion

        #region 反射设置缓存
        /// <summary>
        /// 执行反射方法
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="methodName">方法名</param>
        /// <param name="args">参数</param>
        /// <returns></returns>
        private object ExecuteReflectMethod(Type type, string methodName, object[] args)
        {
            using (ICacheClient cacheClient = GetClient())
            {
                Type tempType = typeof(TempRedisClass<>);
                Type relectType = tempType.MakeGenericType(new Type[] { type });
                //实例化对象
                object obj = Activator.CreateInstance(relectType, new object[] { cacheClient });
                MethodInfo method = relectType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public);
                //反射执行方法
                FastInvoke.FastInvokeHandler fastInvoker = FastInvoke.GetMethodInvoker(method);
                object executedObj = fastInvoker(obj, args);
                return executedObj;
            }
        }

        /// <summary>
        /// 设置缓存值
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        private void SetCache(string key, object value)
        {
            ExecuteReflectMethod(value.GetType(), "Set", new object[] { key, value });
        }

        /// <summary>
        /// 设置缓存值
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        /// <param name="slidingExpiration">过期时间长</param>
        private void SetTimeoutCache(string key, object value, TimeSpan slidingExpiration)
        {
            ExecuteReflectMethod(value.GetType(), "SetTimeoutCache", new object[] { key, value, slidingExpiration });
        }

        /// <summary>
        /// 设置缓存值
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        /// <param name="absoluteExpiration">过期时间</param>
        private void SetDateTimeCache(string key, object value, DateTime absoluteExpiration)
        {
            ExecuteReflectMethod(value.GetType(), "SetDateTimeCache", new object[] { key, value, absoluteExpiration });
        }
        #endregion

        #endregion

        #region 公有函数
        /// <summary>
        /// 发布订阅初始化
        /// </summary>
        public static void PubSubscrInit()
        {
            if (_isPubSubscrInited) //已经初始化了
                return;
            try
            {
                #region 订阅消息处理
                Action<string, string> HandleMsg = (string channel, string msg) =>
                {
                    //可接收的缓存变更订阅远程站点集合，多个以逗号分隔
                    string canReceiveHosts = WebConfigHelper.GetAppSettingValue("CanReceiveCacheHosts");
                    List<string> receiveHostsToken = new List<string>();
                    if (!string.IsNullOrEmpty(canReceiveHosts))
                        receiveHostsToken = canReceiveHosts.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
                    //判断是否满足条件
                    if (channel == UPDATE_CACHE_CHANNEL && receiveHostsToken != null && receiveHostsToken.Count > 0 &&
                        BindUpdateCacheEvent != null && !string.IsNullOrEmpty(msg))
                    {
                        string[] token = msg.Split(SPLIT_CHAR.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        if (token.Length >= 3)
                        {
                            string key = token[0]; //key
                            string ip = token[1]; //远程站点IP
                            string host = token[2]; //远程站点基地址
                            string op = string.Empty;
                            string jsonData = string.Empty;
                            if (token.Length == 5)
                            {
                                op = token[3]; //操作类型
                                jsonData = token[4]; //操作数据
                            }
                            if (ip != IpAddressHelper.GetLocalIp() || host != Globals.GetBaseUrl() && receiveHostsToken.Contains(host))
                            {
                                BindUpdateCacheEvent(null, new UpdateCacheEventArgs(key, ip, host, op, jsonData)); //调用缓存更新事件
                            }
                        }
                    }
                };
                #endregion
                if (!IsRabbitMqCanConn()) //rabbitmq不可用时采用redis自带的发布订阅功能
                {
                    #region redis发布订阅初始化
                    if (subscrRedisClient == null || publishRedisClient == null)
                    {
                        RedisEndpoint redisEndPoint = null;
                        try
                        {
                            string path = WebHelper.GetConfigFilePath("rediscache.config");
                            RedisConfigInfo configInfo = (RedisConfigInfo)XmlHelper.DeserializeFromXML(typeof(RedisConfigInfo), path);
                            if (configInfo != null)
                            {
                                string pwd = string.IsNullOrEmpty(configInfo.Pwd) ? null : configInfo.Pwd;
                                redisEndPoint = new RedisEndpoint(configInfo.Host, configInfo.Port, pwd, configInfo.InitalDB);
                            }
                        }
                        catch { }
                        if (redisEndPoint != null)
                        {
                            if (subscrRedisClient == null) //订阅客户端初始化
                            {
                                #region 订阅客户端初始化
                                subscrRedisClient = new RedisClient(redisEndPoint);
                                Task.Factory.StartNew(() =>
                                {
                                    try
                                    {
                                        IRedisSubscription subscription = subscrRedisClient.CreateSubscription();
                                        //接受到消息时的委托
                                        subscription.OnMessage = (channel, msg) =>
                                        {
                                            HandleMsg(channel, msg);
                                        };
                                        //订阅事件处理
                                        subscription.OnSubscribe = channel => { };
                                        //取消订阅事件处理
                                        subscription.OnUnSubscribe = channel => { };
                                        //订阅频道
                                        subscription.SubscribeToChannels(UPDATE_CACHE_CHANNEL);
                                    }
                                    catch { }
                                });
                                #endregion
                            }
                            if (publishRedisClient == null) //发布客户端初始化
                            {
                                publishRedisClient = new RedisClient(redisEndPoint);
                            }
                            _isPubSubscrInited = true;
                        }
                    }
                    #endregion
                }
                else //使用rabbitmq发布订阅功能
                {
                    #region rabbitmq订阅初始化
                    Task.Factory.StartNew(() =>
                    {
                        using (var conn = GetRabbitMqConn())
                        {
                            _isPubSubscrInited = true;
                            using (var channel = conn.CreateModel())
                            {
                                //声明exchange
                                channel.ExchangeDeclare(RABBIT_EXCHANGE, "fanout", durable);
                                //声明队列
                                var declareResult = channel.QueueDeclare(string.Empty, durable, true, false, null);
                                //绑定队列
                                channel.QueueBind(declareResult.QueueName, RABBIT_EXCHANGE, string.Empty);
                                //定义消费者
                                QueueingBasicConsumer consumer = new QueueingBasicConsumer(channel);
                                //开始消费
                                channel.BasicConsume(declareResult.QueueName, true, consumer);
                                while (true)
                                {
                                    BasicDeliverEventArgs ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                                    var message = Encoding.UTF8.GetString(ea.Body);
                                    if (!string.IsNullOrEmpty(message))
                                    {
                                        HandleMsg(UPDATE_CACHE_CHANNEL, message); //处理消息
                                    }
                                }
                            }
                        }
                    });
                    #endregion
                }
            }
            catch { }
        }

        /// <summary>
        /// 同步各系统数据缓存（内存缓存），针对共享数据，一个系统的内存数据变更时
        /// 通知其他各系统变更相应的内存数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="t">数据对象</param>
        /// <param name="op">对内存缓存的操作，add-新增，edit-编辑，del-删除，rm-移除缓存</param>
        public static void SynchroWebCache<T>(string key, T t, string op) where T : class,new()
        {
            try
            {
                Type type = typeof(T);
                if (type.IsGenericType && type.GetGenericArguments().Length == 1)
                {
                    Type modelType = type.GetGenericArguments().FirstOrDefault();
                    if (modelType != null && modelType.BaseType != null && modelType.BaseType.Name == "BaseLogEntity")
                    {
                        return; //日志类的不同步缓存
                    }
                }
                if (!IsRabbitMqCanConn()) //采用redis发布
                {
                    if (publishRedisClient == null)
                    {
                        PubSubscrInit(); //发布订阅初始化
                    }
                    if (publishRedisClient != null)
                    {
                        try
                        {
                            string jsonData = MySecurity.EncodeBase64(JsonHelper.Serialize(t));
                            string msg = string.Format("{0}{1}{2}{1}{3}{1}{4}{1}{5}", key, SPLIT_CHAR, IpAddressHelper.GetLocalIp(), Globals.GetBaseUrl(), op, jsonData);
                            long ln = publishRedisClient.PublishMessage(UPDATE_CACHE_CHANNEL, msg);
                        }
                        catch { }
                    }
                }
                else //采用rabbitmq发布
                {
                    try
                    {
                        using (var conn = GetRabbitMqConn())
                        {
                            using (var channel = conn.CreateModel())
                            {
                                //声明exchange
                                channel.ExchangeDeclare(RABBIT_EXCHANGE, "fanout", durable);
                                //队列持久化
                                var properties = channel.CreateBasicProperties();
                                properties.Persistent = true;
                                //发布消息
                                string jsonData = MySecurity.EncodeBase64(JsonHelper.Serialize(t));
                                string msg = string.Format("{0}{1}{2}{1}{3}{1}{4}{1}{5}", key, SPLIT_CHAR, IpAddressHelper.GetLocalIp(), Globals.GetBaseUrl(), op, jsonData);
                                var body = Encoding.UTF8.GetBytes(msg);
                                channel.BasicPublish(RABBIT_EXCHANGE, string.Empty, properties, body);
                            }
                        }
                    }
                    catch { }
                }
            }
            catch { }
        }
        #endregion

        #region 单键值
        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public void Add(string key, object value)
        {
            SetCache(key, value);
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public void Add<T>(string key, T value)
        {
            if (!IsConnRedis) return;
            try
            {
                bool rs = false;
                using (ICacheClient cacheClient = GetClient())
                {
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        rs = cacheClient.Set<T>(key, value);
                    }
                }
                if (rs)
                {
                    if (publishRedisClient != null)
                    {
                        try
                        {
                            string msg = string.Format("{0}{1}{2}{1}{3}", key, SPLIT_CHAR, IpAddressHelper.GetLocalIp(), Globals.GetBaseUrl());
                            publishRedisClient.PublishMessage(UPDATE_CACHE_CHANNEL, msg);
                        }
                        catch { }
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Add(string key, object value, TimeSpan slidingExpiration)
        {
            SetTimeoutCache(key, value, slidingExpiration);
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Add<T>(string key, T value, TimeSpan slidingExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<T>(key, value, slidingExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Add(string key, object value, DateTime absoluteExpiration)
        {
            SetDateTimeCache(key, value, absoluteExpiration);
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Add<T>(string key, T value, DateTime absoluteExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<T>(key, value, absoluteExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public void Set(string key, object value)
        {
            SetCache(key, value);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public void Set<T>(string key, T value)
        {
            if (!IsConnRedis) return;
            try
            {
                bool rs = false;
                using (ICacheClient cacheClient = GetClient())
                {
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        rs = cacheClient.Set<T>(key, value);
                    }
                }
                if (rs)
                {
                    if (publishRedisClient != null)
                    {
                        try
                        {
                            string msg = string.Format("{0}{1}{2}{1}{3}", key, SPLIT_CHAR, IpAddressHelper.GetLocalIp(), Globals.GetBaseUrl());
                            publishRedisClient.PublishMessage(UPDATE_CACHE_CHANNEL, msg);
                        }
                        catch { }
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Set(string key, object value, TimeSpan slidingExpiration)
        {
            SetTimeoutCache(key, value, slidingExpiration);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Set<T>(string key, T value, TimeSpan slidingExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<T>(key, value, slidingExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Set(string key, object value, DateTime absoluteExpiration)
        {
            SetDateTimeCache(key, value, absoluteExpiration);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Set<T>(string key, T value, DateTime absoluteExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<T>(key, value, absoluteExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            if (!IsConnRedis)
                return default(T);
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    return cacheClient.Get<T>(key);
                }
            }
            catch { }
            return default(T);
        }

        /// <summary>
        /// 取缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public object Get(string key)
        {
            if (!IsConnRedis) return null;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    return cacheClient.Get<object>(key);
                }
            }
            catch { }
            return null;
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">键</param>
        public void Remove(string key)
        {
            if (!IsConnRedis) return;
            try
            {
                bool rs = false;
                using (ICacheClient cacheClient = GetClient())
                {
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        rs = cacheClient.Remove(key);
                    }
                }
                if (rs)
                {
                    if (publishRedisClient != null)
                    {
                        try
                        {
                            string msg = string.Format("{0}{1}{2}{1}{3}", key, SPLIT_CHAR, IpAddressHelper.GetLocalIp(), Globals.GetBaseUrl());
                            publishRedisClient.PublishMessage(UPDATE_CACHE_CHANNEL, msg);
                        }
                        catch { }
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 缓存是否存在
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public bool Exists(string key)
        {
            object obj = Get(key);
            return obj != null;
        }

        /// <summary>
        /// 刷新缓存
        /// </summary>
        public void FlushAll()
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    cacheClient.FlushAll();
                }
            }
            catch { }
        }
        #endregion

        #region 双键值
        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        public void Add(string key, string valKey, object value)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, object> tempDict = cacheClient.Get<Dictionary<string, object>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        tempDict[valKey] = value;
                    }
                    else
                    {
                        tempDict = new Dictionary<string, object>();
                        tempDict.Add(valKey, value);
                    }
                    SetCache(key, tempDict);
                }
            }
            catch { }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        public void Add<T>(string key, string valKey, T value)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, T> tempDict = cacheClient.Get<Dictionary<string, T>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        tempDict[valKey] = value;
                    }
                    else
                    {
                        tempDict = new Dictionary<string, T>();
                        tempDict.Add(valKey, value);
                    }
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<Dictionary<string, T>>(key, tempDict);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Add(string key, string valKey, object value, TimeSpan slidingExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, object> tempDict = cacheClient.Get<Dictionary<string, object>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        tempDict[valKey] = value;
                    }
                    else
                    {
                        tempDict = new Dictionary<string, object>();
                        tempDict.Add(valKey, value);
                    }
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<Dictionary<string, object>>(key, tempDict, slidingExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Add<T>(string key, string valKey, T value, TimeSpan slidingExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, T> tempDict = cacheClient.Get<Dictionary<string, T>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        tempDict[valKey] = value;
                    }
                    else
                    {
                        tempDict = new Dictionary<string, T>();
                        tempDict.Add(valKey, value);
                    }
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<Dictionary<string, T>>(key, tempDict, slidingExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Add(string key, string valKey, object value, DateTime absoluteExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, object> tempDict = cacheClient.Get<Dictionary<string, object>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        tempDict[valKey] = value;
                    }
                    else
                    {
                        tempDict = new Dictionary<string, object>();
                        tempDict.Add(valKey, value);
                    }
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<Dictionary<string, object>>(key, tempDict, absoluteExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Add<T>(string key, string valKey, T value, DateTime absoluteExpiration)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, T> tempDict = cacheClient.Get<Dictionary<string, T>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        tempDict[valKey] = value;
                    }
                    else
                    {
                        tempDict = new Dictionary<string, T>();
                        tempDict.Add(valKey, value);
                    }
                    using (((RedisClient)cacheClient).AcquireLock(key))
                    {
                        cacheClient.Set<Dictionary<string, T>>(key, tempDict, absoluteExpiration);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        public void Set(string key, string valKey, object value)
        {
            Add(key, valKey, value);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        public void Set<T>(string key, string valKey, T value)
        {
            Add<T>(key, valKey, value);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Set(string key, string valKey, object value, TimeSpan slidingExpiration)
        {
            Add(key, valKey, value);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="slidingExpiration">过期时间</param>
        public void Set<T>(string key, string valKey, T value, TimeSpan slidingExpiration)
        {
            Add<T>(key, valKey, value, slidingExpiration);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Set(string key, string valKey, object value, DateTime absoluteExpiration)
        {
            Add(key, valKey, value, absoluteExpiration);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <param name="value">值</param>
        /// <param name="absoluteExpiration">过期时间</param>
        public void Set<T>(string key, string valKey, T value, DateTime absoluteExpiration)
        {
            Add<T>(key, valKey, value, absoluteExpiration);
        }

        /// <summary>
        /// 取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <returns></returns>
        public T Get<T>(string key, string valKey)
        {
            if (!IsConnRedis) return default(T);
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, T> tempDict = cacheClient.Get<Dictionary<string, T>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        return tempDict[valKey];
                    }
                }
            }
            catch { }
            return default(T);
        }

        /// <summary>
        /// 取缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <returns></returns>
        public object Get(string key, string valKey)
        {
            if (!IsConnRedis) return null;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, object> tempDict = cacheClient.Get<Dictionary<string, object>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        return tempDict[valKey];
                    }
                }
            }
            catch { }
            return null;
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        public void Remove(string key, string valKey)
        {
            if (!IsConnRedis) return;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, object> tempDict = cacheClient.Get<Dictionary<string, object>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        tempDict.Remove(valKey);
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// 缓存是否存在
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="valKey">键</param>
        /// <returns></returns>
        public bool Exists(string key, string valKey)
        {
            if (!IsConnRedis) return false;
            try
            {
                using (ICacheClient cacheClient = GetClient())
                {
                    Dictionary<string, object> tempDict = cacheClient.Get<Dictionary<string, object>>(key);
                    if (tempDict != null) //缓存存在
                    {
                        return tempDict.ContainsKey(valKey);
                    }
                }
            }
            catch { }
            return false;
        }
        #endregion
    }
}
